home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / ostruct.rb < prev    next >
Text File  |  2007-02-12  |  3KB  |  147 lines

  1. #
  2. # = ostruct.rb: OpenStruct implementation
  3. #
  4. # Author:: Yukihiro Matsumoto
  5. # Documentation:: Gavin Sinclair
  6. #
  7. # OpenStruct allows the creation of data objects with arbitrary attributes.
  8. # See OpenStruct for an example.
  9. #
  10.  
  11. #
  12. # OpenStruct allows you to create data objects and set arbitrary attributes.
  13. # For example:
  14. #
  15. #   require 'ostruct' 
  16. #
  17. #   record = OpenStruct.new
  18. #   record.name    = "John Smith"
  19. #   record.age     = 70
  20. #   record.pension = 300
  21. #   
  22. #   puts record.name     # -> "John Smith"
  23. #   puts record.address  # -> nil
  24. #
  25. # It is like a hash with a different way to access the data.  In fact, it is
  26. # implemented with a hash, and you can initialize it with one.
  27. #
  28. #   hash = { "country" => "Australia", :population => 20_000_000 }
  29. #   data = OpenStruct.new(hash)
  30. #
  31. #   p data        # -> <OpenStruct country="Australia" population=20000000>
  32. #
  33. class OpenStruct
  34.   #
  35.   # Create a new OpenStruct object.  The optional +hash+, if given, will
  36.   # generate attributes and values.  For example.
  37.   #
  38.   #   require 'ostruct'
  39.   #   hash = { "country" => "Australia", :population => 20_000_000 }
  40.   #   data = OpenStruct.new(hash)
  41.   #
  42.   #   p data        # -> <OpenStruct country="Australia" population=20000000>
  43.   #
  44.   # By default, the resulting OpenStruct object will have no attributes. 
  45.   #
  46.   def initialize(hash=nil)
  47.     @table = {}
  48.     if hash
  49.       for k,v in hash
  50.         @table[k.to_sym] = v
  51.         new_ostruct_member(k)
  52.       end
  53.     end
  54.   end
  55.  
  56.   # Duplicate an OpenStruct object members. 
  57.   def initialize_copy(orig)
  58.     super
  59.     @table = @table.dup
  60.   end
  61.  
  62.   def marshal_dump
  63.     @table
  64.   end
  65.   def marshal_load(x)
  66.     @table = x
  67.     @table.each_key{|key| new_ostruct_member(key)}
  68.   end
  69.  
  70.   def new_ostruct_member(name)
  71.     name = name.to_sym
  72.     unless self.respond_to?(name)
  73.       meta = class << self; self; end
  74.       meta.send(:define_method, name) { @table[name] }
  75.       meta.send(:define_method, :"#{name}=") { |x| @table[name] = x }
  76.     end
  77.   end
  78.  
  79.   def method_missing(mid, *args) # :nodoc:
  80.     mname = mid.id2name
  81.     len = args.length
  82.     if mname =~ /=$/
  83.       if len != 1
  84.         raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
  85.       end
  86.       if self.frozen?
  87.         raise TypeError, "can't modify frozen #{self.class}", caller(1)
  88.       end
  89.       mname.chop!
  90.       self.new_ostruct_member(mname)
  91.       @table[mname.intern] = args[0]
  92.     elsif len == 0
  93.       @table[mid]
  94.     else
  95.       raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
  96.     end
  97.   end
  98.  
  99.   #
  100.   # Remove the named field from the object.
  101.   #
  102.   def delete_field(name)
  103.     @table.delete name.to_sym
  104.   end
  105.  
  106.   InspectKey = :__inspect_key__ # :nodoc:
  107.  
  108.   #
  109.   # Returns a string containing a detailed summary of the keys and values.
  110.   #
  111.   def inspect
  112.     str = "#<#{self.class}"
  113.  
  114.     Thread.current[InspectKey] ||= []
  115.     if Thread.current[InspectKey].include?(self) then
  116.       str << " ..."
  117.     else
  118.       first = true
  119.       for k,v in @table
  120.         str << "," unless first
  121.         first = false
  122.  
  123.         Thread.current[InspectKey] << v
  124.         begin
  125.           str << " #{k}=#{v.inspect}"
  126.         ensure
  127.           Thread.current[InspectKey].pop
  128.         end
  129.       end
  130.     end
  131.  
  132.     str << ">"
  133.   end
  134.   alias :to_s :inspect
  135.  
  136.   attr_reader :table # :nodoc:
  137.   protected :table
  138.  
  139.   #
  140.   # Compare this object and +other+ for equality.
  141.   #
  142.   def ==(other)
  143.     return false unless(other.kind_of?(OpenStruct))
  144.     return @table == other.table
  145.   end
  146. end
  147.